#include <oatpp/network/Server.hpp>
#include <oatpp-websocket/ConnectionHandler.hpp>
#include <oatpp/web/server/HttpConnectionHandler.hpp>
#include <oatpp/web/server/HttpRouter.hpp>
#include <oatpp/network/tcp/server/ConnectionProvider.hpp>
#include <oatpp/parser/json/mapping/ObjectMapper.hpp>
#include <oatpp/core/macro/component.hpp>
#include <functional>
#include "WSListener.h"
#include "ServerController.h"
#include "ServerHandle.h"

class AppComponent
{
private:
    ServerHandle* serverHandle;
public:
    AppComponent(ServerHandle* _serverHandle) : serverHandle(_serverHandle) {}
        /**
     *  Create ConnectionProvider component which listens on the port
     */
    OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([] {
        return oatpp::network::tcp::server::ConnectionProvider::createShared({"0.0.0.0", 7600, oatpp::network::Address::IP_4},true);
    }());

    /**
     *  Create Router component
     */
    OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
        return oatpp::web::server::HttpRouter::createShared();
    }());

    /**
     *  Create http ConnectionHandler
     */
    OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, httpConnectionHandler)("http" /* qualifier */, [] {
        OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component
        return oatpp::web::server::HttpConnectionHandler::createShared(router);
    }());

    /**
     *  Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API
     */
    OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, apiObjectMapper)([] {
        return oatpp::parser::json::mapping::ObjectMapper::createShared();
    }());

    /**
     *  Create websocket connection handler
     */
    OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, websocketConnectionHandler)("websocket" /* qualifier */, [this] {
        auto connectionHandler = oatpp::websocket::ConnectionHandler::createShared();
        connectionHandler->setSocketInstanceListener(std::make_shared<WSInstanceListener>(serverHandle));
        return connectionHandler;
    }());
};

class ServerCore
{
public:
    ServerCore(ServerHandle* _serverHandle);
    void StopServer();
    virtual ~ServerCore();
    void operator()();
private:
    ServerHandle* serverHandle;
    std::unique_ptr<oatpp::network::Server> server;
};